﻿#include "DXUT.h"
#include "MaterialShader.h"
#include "SDKmisc.h"
#include <stdarg.h>
CMaterialShader::~CMaterialShader(void)
{
}

void CMaterialShader::InitParametersHandle()
{
	//Matrix

	m_world=m_pEffect->GetParameterBySemantic(0,"WORLD");
	m_view=m_pEffect->GetParameterBySemantic(0,"VIEW");
	m_proj=m_pEffect->GetParameterBySemantic(0,"PROJECTION");

	m_worldView=m_pEffect->GetParameterBySemantic(0,"WORLDVIEW ");
	m_worldViewProj=m_pEffect->GetParameterBySemantic(0,"WORLDVIEWPROJECTION");
	m_viewProj=m_pEffect->GetParameterBySemantic(0,"VIEWPROJECTION");
	m_worldViewInverse=m_pEffect->GetParameterBySemantic(0,"WORLDVIEWINVERSE");
	m_viewInverse=m_pEffect->GetParameterBySemantic(0,"VIEWINVERSE");

	//D3DXVECTOR4

	m_lightDir=m_pEffect->GetParameterBySemantic(0,"DIRECTION");
	m_ambientColor=m_pEffect->GetParameterBySemantic(0,"AMBIENT");
	m_diffuseColor=m_pEffect->GetParameterBySemantic(0,"DIFFUSE");
	m_specularColor=m_pEffect->GetParameterBySemantic(0,"SPECULAR");

	//float
	m_shininess=m_pEffect->GetParameterBySemantic(0,"SPECULARPOWER");

	//Texture
	m_diffuseTexture=m_pEffect->GetParameterBySemantic(0,"DIFFUSEMAP");
	m_normalTexture=m_pEffect->GetParameterBySemantic(0,"NORMAL");
	m_heightTexture=m_pEffect->GetParameterBySemantic(0,"HEIGHT");
	m_cubeTexture=m_pEffect->GetParameterBySemantic(0,"ENVIRONMENT");


}

void CMaterialShader::ResetParameters()
{



	m_lastView=
		m_lastProj=
		m_lastWorldView=
		m_lastWorldViewProj=
		m_lastViewProj=
		m_lastWorldViewInverse=
		m_lastViewInverse=
		m_lastWorld=D3DXMATRIX();

	m_lastLightDir=D3DXVECTOR4(0,0,0,0);
	m_lastAmbientColor=m_lastDiffuseColor=m_lastSpecularColor=D3DXCOLOR(-1,-1,-1,-1);
	m_lastShininess=0.0f;
	m_lastDiffseTexture=m_lastNormalTexture=m_lastHeightTexture=0;

	m_lastCubeTexture=0;

}

CMaterialShader::CMaterialShader( const TCHAR * resName,const TCHAR * szFilePath, D3DPOOL pool/*=D3DPOOL_DEFAULT*/ )
	:CGraphicsFileResource(RESOURCE_TYPE_MATERIALSHADER,resName,szFilePath,pool)
		 
{



	m_world=NULL;
	m_view=NULL;
	m_proj=NULL;

	m_worldView=NULL;
	m_worldViewProj=NULL;
	m_viewProj=NULL;
	m_worldViewInverse=NULL;
	m_viewInverse=NULL;

	//D3DXVECTOR4

	m_lightDir=NULL;
	m_ambientColor=NULL;
	m_diffuseColor=NULL;
	m_specularColor=NULL;

	//float
	m_shininess=NULL;

	//Texture
	m_diffuseTexture=NULL;
	m_normalTexture=NULL;
	m_heightTexture=NULL;
	m_cubeTexture=NULL;
	this->ResetParameters();
}

HRESULT CMaterialShader::OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice )
{
	HRESULT hr;
	WCHAR wszPath[MAX_PATH];

	V_RETURN(  DXUTFindDXSDKMediaFileCch( wszPath, MAX_PATH, this->GetFileName() ) ) ;


	LPD3DXBUFFER  pError;
	hr = D3DXCreateEffectFromFile( pd3dDevice,
		wszPath,
		NULL,
		NULL,
		0,
		0,
		&m_pEffect,
		&pError );

	if( FAILED(hr))
	{

		MessageBoxA(0,(char*)pError->GetBufferPointer(),0,0);
		pError->Release();
		return hr;

	}


	hr = m_pEffect->FindNextValidTechnique(NULL, &m_hTechnique);
	if( FAILED( hr ) )
	{
		DXTRACE_ERR_MSGBOX(DXGetErrorString(hr),hr);
		SAFE_RELEASE(m_pEffect);
		return hr;
	}
	V_RETURN(m_pEffect->SetTechnique(m_hTechnique) );

	this->InitParametersHandle();
	return hr;

}

void CMaterialShader::OnD3D9DestroyDevice()
{
	SAFE_RELEASE( m_pEffect);
}

HRESULT CMaterialShader::OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice )
{
	return m_pEffect->OnResetDevice();

}

void CMaterialShader::OnD3D9LostDevice()
{
	m_pEffect->OnLostDevice();

}

inline LPD3DXEFFECT CMaterialShader::GetEffect()
{
	return m_pEffect;
}

void CMaterialShader::SetWorldMatrix( const D3DXMATRIX & matWorld )
{
	if(m_world==NULL ||m_lastWorld==matWorld)
		return;

	m_pEffect->SetMatrix(m_world,&matWorld);
	m_lastWorld=matWorld;

}

void CMaterialShader::SetViewMatrix( const D3DXMATRIX & matView )
{

	if( m_view==NULL || m_lastView==matView)
		return;

	m_pEffect->SetMatrix(m_view,&matView);
	m_lastView=matView;
}

void CMaterialShader::SetProjMatrix( const D3DXMATRIX & matProj )
{
	if(m_proj==NULL ||m_lastProj==matProj)
		return;

	m_pEffect->SetMatrix(m_proj,&matProj);
	m_lastProj=matProj;
}

void CMaterialShader::SetWorldViewMatrix( const D3DXMATRIX & matWorldView )
{

	if(m_worldView==NULL || m_lastWorldView==matWorldView)
		return;

	m_pEffect->SetMatrix(m_worldView,&matWorldView);
	m_lastWorldView=matWorldView;
}

void CMaterialShader::SetWorldViewProjMatrix( const D3DXMATRIX & matWorldViewProj )
{
	if(m_worldViewProj==NULL ||m_lastWorldViewProj==matWorldViewProj)
		return;

	m_pEffect->SetMatrix(m_worldViewProj,&matWorldViewProj);
	m_lastWorldViewProj=matWorldViewProj;
}

void CMaterialShader::SetViewProjMatrix( const D3DXMATRIX & matViewProj )
{
	if(m_viewProj==NULL ||m_lastViewProj==matViewProj)
		return;

	m_pEffect->SetMatrix(m_viewProj,&matViewProj);
	m_lastViewProj=matViewProj;
}

void CMaterialShader::SetWorldViewInverseMatrix( const D3DXMATRIX & matWorldViewInverse )
{
	if(m_worldViewInverse==NULL ||m_lastWorldViewInverse==matWorldViewInverse)
		return;

	m_pEffect->SetMatrix(m_worldViewInverse,&matWorldViewInverse);
	m_lastWorldViewInverse=matWorldViewInverse;
}

void CMaterialShader::SetViewInverseMatrix( const D3DXMATRIX & matViewInverse )
{
	if( m_viewInverse==NULL ||m_lastViewInverse==matViewInverse)
		return;

	m_pEffect->SetMatrix(m_viewInverse,&matViewInverse);
	m_lastViewInverse=matViewInverse;
}

void CMaterialShader::SetLightDir( const D3DXVECTOR4 & vecLightDir )
{
	if(m_lightDir==NULL ||  m_lastLightDir==vecLightDir)
		return ;
	m_pEffect->SetVector(m_lightDir,&vecLightDir);
	m_lastLightDir=vecLightDir;

}

void CMaterialShader::SetAmbientColor( const D3DXCOLOR & AmbientColor )
{
	if(m_ambientColor==NULL ||  m_lastAmbientColor==AmbientColor)
		return ;

	m_pEffect->SetFloatArray(m_ambientColor,(float *)&AmbientColor,4);
	m_lastAmbientColor=AmbientColor;

}

void CMaterialShader::SetDiffuseColor( const D3DXCOLOR & DiffuseColor )
{
	if(  (m_diffuseColor==NULL)||  (m_lastDiffuseColor==DiffuseColor))
		return ;
	m_pEffect->SetFloatArray(m_diffuseColor,(float *)&DiffuseColor,4);
	m_lastDiffuseColor=DiffuseColor;
}

void CMaterialShader::SetSpecularColor( const D3DXCOLOR & SpecularColor )
{
	if( (m_specularColor==NULL)|| (m_lastSpecularColor==SpecularColor))
		return ;

	m_pEffect->SetFloatArray(m_specularColor,(float *)&SpecularColor,4);
	m_lastSpecularColor=SpecularColor;
}

void CMaterialShader:: SetSpecularPower(const  float & shininess)
{

	if( (m_shininess==NULL)|| (m_lastShininess==shininess))
		return ;
	m_pEffect->SetFloat(m_shininess,shininess);
	m_lastShininess=shininess;
}

void CMaterialShader::SetDiffseTexture( LPDIRECT3DTEXTURE9 pDiffuseTexture )
{


	if( (m_diffuseTexture==NULL)|| (m_lastDiffseTexture==pDiffuseTexture))
		return ;

	m_pEffect->SetTexture(m_diffuseTexture,pDiffuseTexture);
	m_lastDiffseTexture=pDiffuseTexture;
}

void CMaterialShader::SetNormalTexture( LPDIRECT3DTEXTURE9 pNormalTexture )
{
	if( (m_normalTexture==NULL)|| (m_lastNormalTexture==pNormalTexture))
		return ;
	m_pEffect->SetTexture(m_normalTexture,pNormalTexture);
	m_lastNormalTexture=pNormalTexture;
}

void CMaterialShader::SetHeightTexture( LPDIRECT3DTEXTURE9 pHeightTexutre )
{
	if( (m_heightTexture==NULL)|| (m_lastHeightTexture==pHeightTexutre))
		return ;
	m_pEffect->SetTexture(m_heightTexture,pHeightTexutre);
	m_lastHeightTexture=pHeightTexutre;
}

void CMaterialShader::SetCubeTexure( LPDIRECT3DCUBETEXTURE9 pCubeTexture )
{


	if ((m_cubeTexture==NULL)||(m_lastCubeTexture==pCubeTexture))
		return ;
	m_pEffect->SetTexture(m_cubeTexture,pCubeTexture);
	m_lastCubeTexture=pCubeTexture;
}

void CMaterialShader::Render( LPCSTR tn,int n,...)
{

	va_list ap;
	va_start ( ap, n );
	UINT iPass;
	D3DXHANDLE   pHt=m_pEffect->GetTechniqueByName(tn); 
	assert(pHt);
	m_pEffect->SetTechnique(tn);
	m_pEffect->Begin(&iPass,0);
	for(int j=0; j<iPass;j++)
	{

		m_pEffect->BeginPass(j);
		for ( int i= 0; i< n; i++ )
		{
			IRenderable* r = va_arg (ap, IRenderable*);
			if (r   )
			{
				r->OnD3D9FrameRender(0);

			}
		}
		m_pEffect->EndPass();
	}
	m_pEffect->End();

}
 
void CMaterialShader::Render( int n,...)
{

	va_list ap;
	va_start ( ap, n );
	UINT iPass;

	m_pEffect->Begin(&iPass,0);
	for(int j=0; j<iPass;j++)
	{

		m_pEffect->BeginPass(j);
		for ( int i= 0; i< n; i++ )
		{
			IRenderable* r = va_arg (ap, IRenderable*);

			if (r )
			{
				r->OnD3D9FrameRender(0);

			}
		}
		m_pEffect->CommitChanges();
		m_pEffect->EndPass();
	}
	m_pEffect->End();

}

void CMaterialShader::Render( IRenderable * pRenderable )
{
	assert(pRenderable); 
	UINT iPass;

	m_pEffect->Begin(&iPass,0);
	for(int j=0; j<iPass;j++)
	{

		m_pEffect->BeginPass(j);

		pRenderable->OnD3D9FrameRender(0);
		m_pEffect->EndPass();

	}

	m_pEffect->End();
}
#pragma region UnitTest
#ifdef _DEBUG
void CMaterialShader::UnitTest()
{
	GameUnitTest* pUnitTest=	new GameUnitTest();

	Singleton<CGame>::Instance()->RunTest(800,600,pUnitTest,pUnitTest);
	SAFE_DELETE(pUnitTest);
}

 



void CMaterialShader::GameUnitTest::OnTerminate( void )
{

	Singleton<CGraphicsResourceManager>::Instance()->RemoveAndDestroy(m_pMaterialShader);
}

HRESULT CMaterialShader::GameUnitTest::OnInitialize( void )
{

	// 添加资源管理器组件
	Singleton<CGame>::Instance()->AddDeviceStateDeposit (Singleton<CGraphicsResourceManager>::Instance());
	Singleton<CGame>::Instance()->AddDeviceStateDeposit(Singleton<CScreenSquare>::Instance());

	//天空盒
	m_pSkyBox=new CSkyBox(TEXT("SpaceSkyCubeMap.dds"));


	Singleton<CGame>::Instance()->AddRenderDeposit(this);
	Singleton<CGame>::Instance()->AddUpdateDeposit(this);
	m_pMaterial = new CMaterial(TEXT("asteroid4.dds"),TEXT("asteroid4Normal.dds"),TEXT("appleHeight.dds"),TEXT("NormalizeCubeMap.dds"),true);
	m_pMaterialShader=new CMaterialShader(TEXT("ParallaxMapping.fx"),TEXT("ParallaxMapping.fx"));
	Singleton<CGraphicsResourceManager>::Instance()->Add((void **)&m_pMaterialShader);
    pMesh =new CMesh(TEXT("Asteroid.X"),TEXT("Asteroid.X"));
	Singleton<CGraphicsResourceManager>::Instance()->Add((void **)&pMesh);

	pMeshInstance=new CMeshInstance(pMesh);
	m_pPlane=new CMeshInstance(pMesh);
	pMeshInstance->SetScale(D3DXVECTOR3(0.1,0.1,0.1));

	pMeshInstance->SetPosition( D3DXVECTOR3(2,0,0));
	m_pPlane->SetPosition(D3DXVECTOR3(-2,0,0));
	pMeshInstance->SetDefaultMateril(false);
	m_pPlane->SetDefaultMateril(true);
	m_Camera= new ICamera();



	pRenderToTexture =new CRenderToTexture(TEXT("RendetToTextureTest"),800,600);
	Singleton<CGraphicsResourceManager>::Instance()->Add((void **) &pRenderToTexture);
	return S_OK;
}

void CMaterialShader::GameUnitTest::OnD3D9FrameRender( float fElapsedTime )
{
	DXUTGetD3D9Device()->SetRenderState(D3DRS_LIGHTING,FALSE);
	m_Camera->DefaultHandle(fElapsedTime);
   D3DXMATRIX matViewInverse;
	D3DXMatrixInverse(&matViewInverse,0,m_Camera->GetViewMatrix());
	m_pSkyBox->SetViewInverse(matViewInverse);
	m_pMaterialShader->SetViewInverseMatrix(matViewInverse);
	 m_pSkyBox->OnD3D9FrameRender(0);
   D3DXMATRIX matWorld;
	D3DXMatrixIdentity(&matWorld);
	m_pMaterialShader->SetWorldMatrix(pMeshInstance->GetWorldMatrix());
	 

	D3DXMATRIX matViewProj=*m_Camera->GetViewMatrix() **m_Camera->GetProjMatrix();
	m_pMaterialShader->SetViewProjMatrix(matViewProj);
	m_Camera->ApplyCamera(DXUTGetD3D9Device());
	m_pMaterial->ApplyMaterial(m_pMaterialShader,&m_pPlane->GetWorldMatrix(),&matViewInverse,&matViewProj);
 	m_pMaterialShader->Render(2,m_pPlane,pMeshInstance);
 





}

void CMaterialShader::GameUnitTest::OnUpdate( double fTime, float fElapsedTime )
{
	if(Singleton<CInput>::Instance()->GetKeyboard()->IsKeyDown(DIK_U))
	{
		pRenderToTexture->RenderWithBeginScene( this);
		pRenderToTexture->SaveToFile(TEXT("RenderToTextureTest.jpg"));
		::ShellExecute(0,0,  TEXT("RenderToTextureTest.jpg"),0,0,0);

	}
	 
}

#endif 
// _DEBUG
#pragma endregion UnitTest 
//UnitTest